
#include <QFile>
#include <QFileInfo>
#include <QSettings>
#include <QRegExp>
#include <cmath>
#include "defaultagent.h"
#include "log.h"
#include "components/chan.h"
#include "components/board.h"
#include "captchafetchers/genericcaptchafetcher.h"
#include "network/request.h"
#include "network/cookiestorage.h"
#include "network/httpconnector.h"
#include "tasks/taskrequest.h"
#include "tasks/taskboardrequest.h"
#include "tasks/taskthreadrequest.h"
#include "tasks/taskthumbnailrequest.h"
#include "tasks/taskattachmentrequest.h"

namespace Wishmaster
{
	DefaultAgent::DefaultAgent(const QString& host) : ChanAgent(host),
		m_host(host), m_captchaFetcher(0)
	{
	}

	void DefaultAgent::setTaskhub(Taskhub* taskhub)
	{
		m_taskhub = taskhub;
	}
	
	Taskhub* DefaultAgent::taskhub()
	{
		return m_taskhub;
	}

	void DefaultAgent::setConnector(Connector* connector)
	{
		HttpConnector* httpconnector = qobject_cast<HttpConnector*>(connector);
		if(httpconnector)
			m_connector = httpconnector;
	}

	HttpConnector* DefaultAgent::connector() const
	{
		return m_connector;
	}

	void DefaultAgent::setCaptchaFetcher(CaptchaFetcher* fetcher)
	{
		if(m_captchaFetcher)
			delete m_captchaFetcher;
		m_captchaFetcher = fetcher;
		if(m_captchaFetcher)
			connect(m_captchaFetcher, SIGNAL(captcha(ThreadId,QByteArray)), this, SLOT(slot_captchaFetcherResult(ThreadId,QByteArray)));
	}

	CaptchaFetcher* DefaultAgent::captchaFetcher() const
	{
		return m_captchaFetcher;
	}

	void DefaultAgent::getCaptcha(const ThreadId& threadId)
	{
		if(!captchaFetcher())
			return;
		captchaFetcher()->fetchCaptcha(threadId);
	}

	QString DefaultAgent::makeThreadLink(const ThreadId& threadId)
	{
		QString threadlink = property("threadlink").toString();
		if(threadlink.isEmpty())
		{
			return QString("%1res/%2.html").arg(threadId.boardId()).arg(threadId.threadStringId());
		}
		threadlink.replace("%BOARD%", threadId.boardId());
		threadlink.replace("%THREADID%", threadId.threadStringId());
		return threadlink;
	}

	void DefaultAgent::requestThread(const ThreadId& threadId, const PostId& lastPostId)
	{
		Q_UNUSED(lastPostId);

		QString reqlink = makeThreadLink(threadId);
		QUrl url("http://" + makeFullHostname(threadId.boardId()) + reqlink);
		TaskThreadRequest* task = new TaskThreadRequest(threadId, url, tr("Requesting thread: %1").arg(threadId.threadNumericId()), connector());
		connect(task, SIGNAL(result(TaskThreadRequest*,QByteArray,QString)), this, SLOT(slot_thread(TaskThreadRequest*,QByteArray,QString)));
		TaskPtr taskptr = TaskPtr(task);
		m_taskhub->queueTask(taskptr);
	}

	void DefaultAgent::requestThumbnail(const PostId& postId, int attachmentIndex, const QUrl& thumblink)
	{
		QUrl link = thumblink;
		if(link.isRelative())
			link.setScheme("http");
		if(link.host().isEmpty())
			link.setHost(m_host);

		TaskThumbnailRequest* task = new TaskThumbnailRequest(postId, attachmentIndex, thumblink,
															  tr("Requesting thumbnail for post: ") + QString::number(postId.postId()), connector());
		connect(task, SIGNAL(result(TaskThumbnailRequest*,QByteArray,QString)), this, SLOT(slot_thumb(TaskThumbnailRequest*,QByteArray,QString)));
		TaskPtr taskptr = TaskPtr(task);
		m_taskhub->queueTask(taskptr);
	}

	void DefaultAgent::requestPic(const PostId& postId, int attachmentIndex, const QUrl& piclink)
	{
		QUrl link = piclink;
		if(link.isRelative())
			link.setScheme("http");
		if(link.host().isEmpty())
			link.setHost(m_host);

		QString taskname;
		if(postId.postId() != 0)
			taskname = tr("Requesting picture for post: ") + QString::number(postId.postId());
		else
			taskname = tr("Requesting picture for thread: ") + QString::number(postId.threadId());
		TaskAttachmentRequest* task = new TaskAttachmentRequest(postId, attachmentIndex,
				link, taskname, connector());
		connect(task, SIGNAL(result(TaskAttachmentRequest*, QByteArray, QString)), this, SLOT(slot_pic(TaskAttachmentRequest*, QByteArray, QString)));
		TaskPtr taskptr = TaskPtr(task);

		QSettings settings;
		bool queuefirst = settings.value("connection/picRequestPriority", true).toBool();
		if(queuefirst)
		{
			m_taskhub->queueTaskFirst(taskptr);
		}
		else
		{
			m_taskhub->queueTask(taskptr);
		}

	}

	void DefaultAgent::downloadFile(const PostId& postId, int attachIndex, const QUrl& filelink, const QString& filename)
	{
		QUrl link = filelink;
		if(link.isRelative())
			link.setScheme("http");
		if(link.host().isEmpty())
			link.setHost(m_host);

//		TaskRequest* task = new TaskRequest(PostId(postId.chan(), postId.board(), postId.threadId(), postId.postId()), attachIndex,
//				link, connector(), tr("Downloading file: ") + link.toString());
//		task->setProperty("filename", filename);
//		connect(task, SIGNAL(requestDone(int, PostId, QByteArray)), this, SLOT(slot_file(int, PostId, QByteArray)));
//		TaskPtr taskptr = TaskPtr(task);
//		m_taskhub->queueTask(taskptr);
	}

	void DefaultAgent::requestBoardIndex(const QString& boardId)
	{
		QUrl url("http://" + makeFullHostname(boardId) + boardId);
		TaskBoardRequest* task = new TaskBoardRequest(m_host, boardId, url,
									 tr("Requesting board index: %1 (%2)").arg(boardId).arg(m_host),
									 connector());

		connect(task, SIGNAL(result(TaskBoardRequest*,QByteArray,QString)), this, SLOT(slot_board(TaskBoardRequest*,QByteArray,QString)));
		TaskPtr taskptr = TaskPtr(task);
		m_taskhub->queueTask(taskptr);
	}


	void DefaultAgent::slot_board(TaskBoardRequest* task, const QByteArray& arr, const QString& contentType)
	{
		if(contentType.isEmpty())
			return; // Most likely, error occured
		if(!contentType.contains("text/html"))
			log(llWarning, "DefaultAgent::slot_board: unexpected content type: %s", qPrintable(contentType));

		log(llDebug, "DefaultAgent::slot_board: board index obtained");
		emit board(task->chanName(), task->boardId(), arr);
	}

	void DefaultAgent::slot_thread(TaskThreadRequest* task, const QByteArray& arr, const QString& contentType)
	{
		if(contentType.isEmpty())
		{
			emit threadDead(task->threadId());
			return;
		}
		log(llDebug, "DefaultAgent::slot_thread: thread content obtained");
		emit thread(task->threadId(), arr);
	}

	void DefaultAgent::slot_thumb(TaskThumbnailRequest* task, const QByteArray& arr, const QString& contentType)
	{
		if(contentType.isEmpty())
			return;
		emit thumb(task->postId(), task->attachmentIndex(), arr);
	}

	void DefaultAgent::slot_pic(TaskAttachmentRequest* task, const QByteArray& arr, const QString& contentType)
	{
		emit attachment(task->postId(), task->attachmentIndex(), arr, contentType);
	}

	
	void DefaultAgent::slot_file(int /*status*/, const PostId& postid, int attachmentIndex, const QByteArray& arr)
	{
		QFile f(sender()->property("filename").toString());
		f.open(QIODevice::WriteOnly);
		f.write(arr);
		f.close();
	}

	void DefaultAgent::slot_captchaFetcherResult(const ThreadId& threadid, const QByteArray& arr)
	{
		log(llDebug, "DefaultAgent::slot_captchaFetcherResult");
		emit captcha(threadid, arr);
	}

	QString DefaultAgent::makeFullHostname(const QString& board)
	{
		QString fullhost = m_host;
		if(property(QString("hostprefix" + board).toUtf8().data()).isValid())
			fullhost.prepend(property(QString("hostprefix" + board).toUtf8().data()).toString());
		return fullhost;
	}

	void DefaultAgent::deleteThread(const ThreadId& /*threadId*/, const QString& /*password*/)
	{
	}

	void DefaultAgent::deletePost(const PostId& /*postId*/, const QString& /*password*/)
	{
	}

	void DefaultAgent::addAttachments(HttpRequestPtr& r, const AttachmentDescriptor& attach, const QString& fieldname)
	{
		if(attach.filename.isEmpty())
		{
			r->addPostFile(fieldname, "", QByteArray());
		}
		else
		{
			QFileInfo info(attach.filename);
			QByteArray data;
			if(attach.useData)
			{
				data = attach.data;
			}
			else
			{
				QFile file(attach.filename);
				if(file.open(QIODevice::ReadOnly))
				{
					data = file.readAll();
				}
			}
			if(data.isEmpty())
			{
				r->addPostFile(fieldname, "", QByteArray());
			}
			else
			{
				foreach(const ExtraInfoDescriptor& extra, attach.extras)
				{
					data.append(extra.info);
				}
				r->addPostFile(fieldname, info.fileName(), data);
			}
		}
	}

	ChanAgent* DefaultAgent::clone(const QString& host)
	{
		return new DefaultAgent(host);
	}

	QString DefaultAgent::id()
	{
		return "default";
	}
}

